/*
 * Mutex.h
 *
 *  Created on: Mar 15, 2011
 *      Author: user
 */

#ifndef __BILBAO_LANG_MUTEX_CLASS_H_
#define __BILBAO_LANG_MUTEX_CLASS_H_

#include "bilbao/types.h"

namespace bilbao
{
	namespace lang
	{
		/** @brief Implements the mutex-based approach to protect data shared by
		 *		multiple threads.
		 *  @remarks
		 *		Threads are waiting for mutexes when using shared data. This means that threads
		 *		tells the mutex they are wanting to access the data protected by the mutex. Thus,
		 *		If the mutex is unlocked, then the thread can proceed its processing and access
		 *		the protected data. Ohterwhise, it waits until the mutex is unlocked to proceed.
		 *  @par
		 *		Once a mutex has been locked, no other thread is allowed to lock the mutex.
		 *  	Only one thread at a time can get access to the mutex, and only the thread
		 *	    that has locked the mutex may use or manipulate the data which the mutex
		 *		protects. To unlock a mutex after its work is done, the thread calls unlock().
		 *
		 *	@see Thread, MutexLocker
		 */
		class Mutex
		{
		public:

			/** Constructor: internally creates the mutex
			 */
			Mutex(void);

			/** Destructor: internally destroys the mutex
			 *  @warning Avoid
			 */
			~Mutex(void);

			/** This method is called by threads wanting to lock this mutex.
			 *  @remarks This method will block the calling thread until the mutex is available.
			 * 			 It could be immediately, if no other thread has locked it.
			 */
			void lock(void);

			/** Unlocks a mutex, telling the blocked threads that data protected by this
			 *  mutex is available.
			 */
			void unlock(void);

			/** Tells whether this mutex is locked.
			 */
			bool isLocked(void) const;

		protected:

			/** Is this mutex locked?
			 */
			bool locked;

			/// Internal mutex handle
			#if BILBAO_PLATAFORM == BILBAO_WIN32
				HANDLE mutex;
			#else
				pthread_mutex_t mutex;
			#endif
		};


		/** @brief Utility class that assures that Mutexes are locked/unlocked properly while the locker object is alive.
		 *
		 *  @remarks
		 *		This utility class helps programmers when they are locking shared data in methods and functions.
		 *		Using this class is very simple:
		 *			- At the constructor, use the desired mutex as argument;
		 *			- At the desconstructor, use given mutex is unlocked. Thus, you don't need to code unlocks in your code and won't forget
		 *			  to unlock the mutex. Have fun! :P
		 *
		 *  @note Remember that your mutex must be valid in the entire "life" of this locker,
		 *		  because this class uses a pointer internally to avoid the destruction of
		 *		  the mutex, so we won't see blue screens.
		 */
		class MutexLocker
		{
		public:

			/** Constructor. Just locks the mutex.
			 */
			MutexLocker( Mutex& mutex );

			/** Destructor: unlocks the mutex
			 */
			~MutexLocker(void);

		private:

			/** @brief Private copy-constructor
			 *
			 *  @remarks MutexLockers are not here to be passed by copy as argument nor
			 *			 to be explicitly copied.
			 */
			MutexLocker( const MutexLocker& locker );

			/** @brief Private copy assignment operator
			 *
			 *  @remarks MutexLockers are not here to be passed by copy as argument nor
			 *			 to be explicitly copied.
			 */
			MutexLocker& operator = ( const MutexLocker& locker );

			/** Mutex that is locked/unlocked internally
			 */
			Mutex& mutex;
		};
	} //namespace lang
} //namespace bilbao

#endif//__BILBAO_LANG_MUTEX_CLASS_H_
